/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

// RgnDialog.cpp : implementation file

#include "stdafx.h"
#include "CHScanner.h"
#include "RgnDialog.h"
#include ".\rgndialog.h"

//---------------------------------------------------------------------------
#define DEFAULT_TRANSPARENCY_PROCENT 30;
//---------------------------------------------------------------------------

IMPLEMENT_DYNAMIC(CRgnDialog, CDialog)
CRgnDialog::CRgnDialog(UINT templateIdIn, CWnd* pParent /*=NULL*/) : CDialog(templateIdIn, pParent)
{
	transparency = DEFAULT_TRANSPARENCY_PROCENT;

	skin = NULL;
	isSizable = false;
	wndCaption.Empty();

	XX = 0;
	YY = 0;
	moving = false;
	sizing = false;

	ctrlMove = NULL;
	ctrlSize = NULL;

	helpInfo = NULL;
}

CRgnDialog::~CRgnDialog()
{
	DestroyMoveControl();
	DestroySizeControl();
}

//---------------------------------------------------------------------------

void CRgnDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

//---------------------------------------------------------------------------

BEGIN_MESSAGE_MAP(CRgnDialog, CDialog)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
	ON_WM_NCPAINT()
	ON_WM_HELPINFO()
END_MESSAGE_MAP()

//---------------------------------------------------------------------------

bool CRgnDialog::SetTransparency(void)
{
	BYTE transp;
	BOOL res;

	res = ModifyStyleEx(0, WS_EX_LAYERED);
	if(!res) return false;

	transp = (BYTE)(int)((255*(100-transparency))/100);
	res = SetLayeredWindowAttributes(0, transp, LWA_ALPHA);

	return res ? true : false;
}

//---------------------------------------------------------------------------

bool CRgnDialog::CreateRegion(void)
{
	RECT rect;
	RECT minSize;
	int ww, hh;
	int dw, dh;		///< difference between minimum required and actual dimensions
	bool res;

	if(skin==NULL) return false;

	GetWindowRect(&rect);
	ww = rect.right - rect.left;
	hh = rect.bottom - rect.top;

	res = skin->rgnWindow.GetClientRectangle(&rect, ww, hh);
	if(!res){
		GetWindowRect(&rect);
		rect.right  -= rect.left;
		rect.right  -= 2;
		rect.bottom -= rect.top;
		rect.bottom -= 20;
		rect.left = 2;
		rect.top  = 20;
//		return false;
	}

	clientRect.left   = rect.left;
	clientRect.top    = rect.top;
	clientRect.right  = rect.right;
	clientRect.bottom = rect.bottom;

	if(GetMinimumSize(&minSize)){
		dw = (minSize.right - minSize.left) - (clientRect.right - clientRect.left);
		dh = (minSize.bottom - minSize.top) - (clientRect.bottom - clientRect.top);

		if(dw<0) dw = 0;
		if(dh<0) dh = 0;

		if(dw>0 || dh>0){
			// resize required
			SetWindowPos(NULL, 0, 0, ww + dw, hh + dh, SWP_NOACTIVATE | SWP_NOMOVE);

			GetWindowRect(&rect);
			ww = rect.right - rect.left;
			hh = rect.bottom - rect.top;

			res  = skin->rgnWindow.GetClientRectangle(&clientRect, ww, hh);
			if(!res) return false;
		}
	}

	ResizeChilds();

	res &= skin->rgnWindow.SetRegion(m_hWnd, ww, hh);

	return res;
}

//---------------------------------------------------------------------------

void CRgnDialog::ResizeChilds(void)
{
}

bool CRgnDialog::GetMinimumSize(RECT*)
{
	return false;
}

//---------------------------------------------------------------------------

void CRgnDialog::StartMoving(int xIn, int yIn)
{
	XX = xIn;
	YY = yIn;
	moving = true;
	sizing = false;

	SetCapture();
}

void CRgnDialog::StartSizing(int xIn, int yIn)
{
	XX = xIn;
	YY = yIn;
	moving = false;
	sizing = true;

	SetCapture();
}

void CRgnDialog::DraggedTo(int xIn, int yIn)
{
	RECT rect;
	int ww, hh;
	int dx, dy, mx, my;

	if(!moving && !sizing) return;

	GetWindowRect(&rect);
	ww = rect.right - rect.left;
	hh = rect.bottom - rect.top;

	if(moving){
		dx = xIn - XX;
		dy = yIn - YY;
		if(dx!=0 || dy!=0)
			SetWindowPos(NULL, rect.left + dx, rect.top + dy, ww, hh, SWP_NOZORDER);
	}
	if(sizing){
		dx = xIn - XX;
		dy = yIn - YY;

		mx = dx>=0 ? dx : -1*dx;
		my = dy>=0 ? dy : -1*dy;

//		CString str;
//		str.Format("%d %d\n", dx, dy);
//		OutputDebugString(str);

		if(mx>=5 || my>=5){
			SetWindowPos(NULL, rect.left, rect.top, ww + dx, hh + dy, SWP_NOZORDER);
			XX += dx;
			YY += dy;

			CreateRegion();
			MoveMoveControl();
			MoveSizeControl();
		}
	}
}

void CRgnDialog::DraggingStopped(void)
{
	if(sizing){
		CreateRegion();
	}

	moving = false;
	sizing = false;

	ReleaseCapture();
}

//---------------------------------------------------------------------------

bool CRgnDialog::CreateMoveControl(void)
{
	return CreateStaticControl(__rgbtMove);
}

bool CRgnDialog::CreateSizeControl(void)
{
	return CreateStaticControl(__rgbtSize);
}

bool CRgnDialog::CreateStaticControl(RgnDialogButtonType typeIn)
{
	CRect rect;
	int ww, hh;
	int imgLeft, imgTop;
	int imgWidth, imgHeight;
	CStatic* ctrl;
	HBITMAP hBmp;

	DestroyStaticControl(typeIn);

	if(skin==NULL){
		// no skin, no buttons
		return true;
	}

	GetWindowRect(&rect);
	ww = rect.Width();
	hh = rect.Height();

	switch(typeIn){
		case __rgbtMove :
			hBmp      = skin->moveImage;
			imgLeft   = skin->moveImgPos.GetX(ww);
			imgTop    = skin->moveImgPos.GetY(hh);
			if(hBmp!=0){
				imgWidth  = skin->moveImage.GetWidth();
				imgHeight = skin->moveImage.GetHeight();
			}
			else{
				imgWidth = 0;
				imgHeight = 0;
			}
			break;

		case __rgbtSize :
			hBmp      = skin->sizeImage;
			imgLeft   = skin->sizeImgPos.GetX(ww);
			imgTop    = skin->sizeImgPos.GetY(hh);
			if(hBmp!=0){
				imgWidth  = skin->sizeImage.GetWidth();
				imgHeight = skin->sizeImage.GetHeight();
			}
			else{
				imgWidth = 0;
				imgHeight = 0;
			}
			break;
	}

	if(imgWidth<=0 || imgHeight<=0){
		// no image, no button
		return true;
	}

	rect.left   = imgLeft;
	rect.top    = imgTop;
	rect.right  = imgLeft + imgWidth;
	rect.bottom = imgTop + imgHeight;
	
	try{
		ctrl = new CStatic;
	}
	catch(...){
		ctrl = NULL;
	}
	if(ctrl==NULL) return false;

	if(!ctrl->Create(_T(""), WS_CHILD | WS_VISIBLE | SS_BITMAP, rect, this)){
		delete ctrl;
		return false;
	}
	
	ctrl->SetBitmap(hBmp);

	switch(typeIn){
		case __rgbtMove :
			ctrlMove = ctrl;
			break;

		case __rgbtSize :
			ctrlSize = ctrl;
			break;
	}

	return true;
}

void CRgnDialog::DestroyMoveControl(void)
{
	DestroyStaticControl(__rgbtMove);
}

void CRgnDialog::DestroySizeControl(void)
{
	DestroyStaticControl(__rgbtSize);
}

void CRgnDialog::DestroyStaticControl(RgnDialogButtonType typeIn)
{
	switch(typeIn){
		case __rgbtMove :
			if(ctrlMove!=NULL){
				ctrlMove->DestroyWindow();
				delete ctrlMove;
				ctrlMove = NULL;
			}
			break;

		case __rgbtSize :
			if(ctrlSize!=NULL){
				ctrlSize->DestroyWindow();
				delete ctrlSize;
				ctrlSize = NULL;
			}
			break;
	}
}

void CRgnDialog::MoveMoveControl(void)
{
	MoveStaticControl(__rgbtMove);
}

void CRgnDialog::MoveSizeControl(void)
{
	MoveStaticControl(__rgbtSize);
}

void CRgnDialog::MoveStaticControl(RgnDialogButtonType typeIn)
{
	CStatic* ctrl;
	CRect rect;
	int left, top;
	int ww, hh;

	if(skin==NULL) return;

	GetWindowRect(&rect);
	ww = rect.Width();
	hh = rect.Height();

	switch(typeIn){
		case __rgbtMove :
			left = skin->moveImgPos.GetX(ww);
			top  = skin->moveImgPos.GetY(hh);
			ctrl = ctrlMove;
			break;

		case __rgbtSize :
			left = skin->sizeImgPos.GetX(ww);
			top  = skin->sizeImgPos.GetY(hh);
			ctrl = ctrlSize;
			break;

		default:
			ctrl = NULL;
			break;
	}

	if(ctrl==NULL) return;

	ctrl->GetWindowRect(&rect);
	rect.MoveToXY(left, top);
	ctrl->SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER);
}

//---------------------------------------------------------------------------

bool CRgnDialog::SetProperties(MSkin *skinIn, bool sizableIn, CString wndCaptionIn)
{
	bool res;

	isSizable  = sizableIn;
	wndCaption = wndCaptionIn;

	if(skinIn==NULL){
		transparency = DEFAULT_TRANSPARENCY_PROCENT;
		SetTransparency();
		CreateRegion();
		return false;
	}

	skin         = skinIn;
	transparency = skin->cwTransparency;

	res  = SetTransparency();
	res &= CreateRegion();

//	CreateMoveControl();
//	CreateSizeControl();

	return res;
}

//---------------------------------------------------------------------------

void CRgnDialog::OnLButtonDown(UINT nFlags, CPoint point)
{
	RECT rect;
	int dx, dy;

	// point is relative to the upper-left corner of the window

	GetWindowRect(&rect);
	dx = rect.right - (point.x + rect.left);
	dy = rect.bottom - (point.y + rect.top);

	CString str;
	if(isSizable && dx<25 && dy<25)
		StartSizing(point.x, point.y);
	else
		StartMoving(point.x, point.y);

	CDialog::OnLButtonDown(nFlags, point);
}

void CRgnDialog::OnLButtonUp(UINT nFlags, CPoint point)
{
	DraggingStopped();

	CDialog::OnLButtonUp(nFlags, point);
}

void CRgnDialog::OnMouseMove(UINT nFlags, CPoint point)
{
	DraggedTo(point.x, point.y);

	CDialog::OnMouseMove(nFlags, point);
}

//---------------------------------------------------------------------------

BOOL CRgnDialog::OnEraseBkgnd(CDC* pDC)
{
	if(pDC==NULL) return FALSE;

	RECT rect;
	CBrush brush;

	if(skin==NULL) brush.CreateSolidBrush(RGB(0, 0, 0xFF));
	else           brush.CreateSolidBrush(skin->cwBackColor);
	UnrealizeObject(brush);

	GetWindowRect(&rect);
	rect.right -= rect.left;
	rect.bottom -= rect.top;
	rect.left = 0;
	rect.top = 0;

	pDC->FillRect(&rect, &brush);

	brush.DeleteObject();

	return TRUE;
}

void CRgnDialog::OnNcPaint()
{
	// TODO: Add your message handler code here
	// Do not call CDialog::OnNcPaint() for painting messages
}

void CRgnDialog::OnPaint()
{
	CPaintDC dc(this); // device context for painting

	RECT rect;
	
	CFont *theFont;
	CFont *oldFont;

	if(!wndCaption.IsEmpty()){
		GetClientRect(&rect);
		rect.left = 4;
		rect.top = 2;

		theFont = GetFont();
		oldFont = dc.SelectObject(theFont);

		dc.SetBkMode(TRANSPARENT);
		if(skin==NULL) dc.SetTextColor(RGB(0xFF, 0xFF, 0x00));
		else           dc.SetTextColor(skin->titleColor);
		dc.DrawText(wndCaption, &rect, DT_LEFT | DT_SINGLELINE | DT_TOP | DT_CALCRECT);
		dc.DrawText(wndCaption, &rect, DT_LEFT | DT_SINGLELINE | DT_TOP);
		
		dc.SelectObject(oldFont);
	}
}

//---------------------------------------------------------------------------

void CRgnDialog::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);

	/*
	CString str;
	str.Format(_T("Size: %d %d\n"), cx, cy);
	OutputDebugString(str);
	*/
}

//---------------------------------------------------------------------------

BOOL CRgnDialog::OnHelpInfo(HELPINFO* pHelpInfo)
{
	if(pHelpInfo==NULL) return FALSE;

	ShowHelp();

	return TRUE;
}

void CRgnDialog::SetHelpInfo(MHelpInfo* helpInfoIn, UINT helpIdIn)
{
	SetHelpID(helpIdIn);
	helpInfo = helpInfoIn;
}

bool CRgnDialog::ShowHelp(void)
{
	if(helpInfo==NULL) return false;

	return helpInfo->ShowHelp(m_nIDHelp);
}

//---------------------------------------------------------------------------
